package com.tianji.learning.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.LearningConstants;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.dto.PointsBoardQuery;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.domain.vo.PointsBoardItemVO;
import com.tianji.learning.domain.vo.PointsBoardVO;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.service.IPointsBoardService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.tianji.learning.constants.LearningConstants.POINT_BOARD_TABLE;

/**
 * <p>
 * 学霸天梯榜 服务实现类
 * </p>
 *
 * @author taohongrun
 * @since 2025-02-11
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class PointsBoardServiceImpl extends ServiceImpl<PointsBoardMapper, PointsBoard> implements IPointsBoardService {
    private final StringRedisTemplate redisTemplate;
    private final UserClient userClient;
    @Override
    public PointsBoardVO queryPointsBoardBySeason(PointsBoardQuery query) {
        Long userId = UserContext.getUser();
        if(query.getSeason() == null || query.getSeason() == 0){
            //本赛季
            LocalDateTime now = LocalDateTime.now();
            String key = getSeasonBoardKey(now);
            List<PointsBoardItemVO> currentSeasonBoard = getCurrentSeasonBoard(query.getPageNo(), query.getPageSize(), now);
            PointsBoardVO pointsBoardVO = new PointsBoardVO();
            pointsBoardVO.setBoardList(currentSeasonBoard);

            //处理本赛季我的排名与分数
            Double score = redisTemplate.opsForZSet().score(key, userId.toString());
            //注意这里rank，要逆序
            Long rank = redisTemplate.opsForZSet().reverseRank(key, userId.toString());
            pointsBoardVO.setPoints(score==null?0:score.intValue());
            //注意排名与索引的关系，rank的排名从0开始
            pointsBoardVO.setRank(rank==null?0:rank.intValue()+1);
            return pointsBoardVO;

        }else {
            //以往赛季
            getHistorySeasonBoard(query.getSeason());

            return null;
        }
    }

    @Override
    public void createPointsBoardTableBySeason(Integer season) {
        getBaseMapper().createPointsBoardTable(POINT_BOARD_TABLE + season);
    }

    @Override
    public List<PointsBoard> queryCurrentBoardList(String key, int pageNo, int pageSize) {
        long start = (pageNo - 1) * pageSize;
        long end = start + pageSize-1;
        log.info("queryCurrentBoardList任务执行查询赛季排行内容，redis key：{}，start：{}，end：{}", key, start, end);
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
        log.info("queryCurrentBoardList任务执行查询赛季排行内容，查询结果：{}",  typedTuples);
        if(typedTuples == null) return CollUtil.empty(PointsBoard.class);
        List<PointsBoard> list = typedTuples.stream().map(tuple -> {
            PointsBoard pointsBoard = new PointsBoard();
            Long rank = redisTemplate.opsForZSet().reverseRank(key, tuple.getValue());
            pointsBoard.setId(rank+1);
            pointsBoard.setUserId(Long.valueOf(tuple.getValue()));
            pointsBoard.setPoints(tuple.getScore().intValue());
            return pointsBoard;
        }).collect(Collectors.toList());
        log.info("queryCurrentBoardList任务执行查询赛季排行内容，转换后的结果：{}",  list);
        return list;
    }

    private List<PointsBoardItemVO> getCurrentSeasonBoard(Integer pageNo, Integer pageSize, LocalDateTime now){
        //确定索引起始位置与结束位置
        long start = (pageNo - 1) * pageSize;
        long end = start + pageSize-1;
        String key = getSeasonBoardKey(now);
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
        if(typedTuples == null) return CollUtil.empty(PointsBoardItemVO.class);

        //获取usermap用于补充信息
        List<Long> userIdList = typedTuples.stream().map(tuple -> Long.valueOf(tuple.getValue())).collect(Collectors.toList());
        Map<Long, String> userMap = userClient.queryUserByIds(userIdList).stream().collect(Collectors.toMap(UserDTO::getId, UserDTO::getName));
        //根据索引起始位置确定排名
        int rank = (int) start + 1;
        List<PointsBoardItemVO> list = new ArrayList<>();
        for(ZSetOperations.TypedTuple<String> tuple : typedTuples){
            PointsBoardItemVO pointsBoardItemVO = new PointsBoardItemVO();
            pointsBoardItemVO.setPoints(tuple.getScore().intValue());
            pointsBoardItemVO.setRank(rank++);
            pointsBoardItemVO.setName(userMap.get(Long.valueOf(tuple.getValue())));
            list.add(pointsBoardItemVO);
        }
        return list;
    }

    private String getSeasonBoardKey( LocalDateTime now){
        return StrUtil.format(RedisConstants.POINTS_BOARD_KEY, DateUtil.format(now, "yyyyMM"));
    }

    private List<PointsBoardItemVO> getHistorySeasonBoard(Long season) {
        // TODO
        return null;
    }
}
